﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using DrawingScreen.Messages;
using DrawingScreen.Constant;

namespace DrawingScreen.Objects
{
    public class CClientDrawingScreen
    {
        private List<CDrawingObject> m_globalDrawingObjects = new List<CDrawingObject>();

        private int mClientID;

        private List<CDrawingObject> m_drawingObjects = new List<CDrawingObject>();

        private int mCount = 0; //  For redoing and undoing

        private int mCurrentMode = CMode.LINE; //LINE, FREEDOM, CIRCLE, RECTANGLE, ELLIPSE, POINTER

        private Pen mCurrentPen = new Pen(Color.Blue, 1);

        private CLine mCurrentline = new CLine();

        private CCircle mCurrentCircle = new CCircle();

        private CEllipse mCurrentEllipse = new CEllipse();

        private CRectangle mCurrentRectangle = new CRectangle();

        private CPointer mCurrentPointer = new CPointer(0);

        private CClipArt mCurrentClipArt = new CClipArt(0);

        public CClientDrawingScreen(int clientID, List<CDrawingObject> globalDrawingObjects)
        {
            this.mClientID = clientID;

            this.m_globalDrawingObjects = globalDrawingObjects;

            Global.InitForNewClient(clientID);

            this.UpdateClientState();

        }

        public void UpdateClientState()
        {
            Pen pen = Global.GetPenByID(mClientID);
            this.mCurrentPen = new Pen(pen.Color, pen.Width);

            this.mCurrentMode = Global.GetModeByID(mClientID);

            int pointerId = Global.GetPointerIDByID(mClientID);
            this.mCurrentPointer = new CPointer(pointerId);

            int caId = Global.GetClipArtIDByID(mClientID);
            this.mCurrentClipArt = new CClipArt(caId);
        }

        public void CreatePen()
        {
            Pen pen = Global.GetPenByID(mClientID);

            this.mCurrentPen = new Pen(pen.Color, pen.Width);

            ResetMode();
        }

        public void ResetMode()
        {
            this.enable_move_up = false;

            Global.prev_ClientID_Mode_dictionary[mClientID] = mCurrentMode;

            this.mCurrentMode = Global.GetModeByID(mClientID);

            Pen pen = new Pen( this.mCurrentPen.Color, this.mCurrentPen.Width);

            if (mCurrentMode == CMode.LINE)
            {
                mCurrentline.pen = pen;
            }
            else if (mCurrentMode == CMode.CIRCLE)
            {
                mCurrentCircle.pen = pen;
            }
            else if (mCurrentMode == CMode.ELLIPSE)
            {
                mCurrentEllipse.pen = pen;
            }
            else if (mCurrentMode == CMode.RECTANGLE)
            {
                mCurrentRectangle.pen = pen;
            }
            else if (mCurrentMode == CMode.POINTER)
            {
                int id = Global.prev_ClientID_PointerID_dictionary[mClientID];
                mCurrentPointer = new CPointer(id);
            }
            else if (mCurrentMode == CMode.CLIPART)
            {
                int id = Global.prev_ClientID_ClipArtID_dictionary[mClientID];
                mCurrentClipArt = new CClipArt(id);
            }
        }

        public void Process(CDrawingMessage message)
        {
            if (message is CDrawingMessage_Action)
            {
                if (mCurrentMode == CMode.LINE)
                {
                    On_CDrawingMessage_Action_LINE((CDrawingMessage_Action)message);
                }
                else if (mCurrentMode == CMode.FREEDOM)
                {
                   On_CDrawingMessage_Action_FREEDOM((CDrawingMessage_Action)message);
                }
                else if (mCurrentMode == CMode.CIRCLE)
                {
                    On_CDrawingMessage_Action_CIRCLE((CDrawingMessage_Action)message);
                }
                else if (mCurrentMode == CMode.ELLIPSE)
                {
                    On_CDrawingMessage_Action_ELLIPSE((CDrawingMessage_Action)message);
                }
                else if (mCurrentMode == CMode.RECTANGLE)
                {
                    On_CDrawingMessage_Action_RECTANGLE((CDrawingMessage_Action)message);
                }
                else if (mCurrentMode == CMode.POINTER)
                {
                    On_CDrawingMessage_Action_POINTER((CDrawingMessage_Action)message);
                }
                else if (mCurrentMode == CMode.CLIPART)
                {
                    On_CDrawingMessage_Action_CLIPART((CDrawingMessage_Action)message);
                }
            }
            else if (message is CDrawingMessage_Redo)
            {
                this.Redo();
            }
            else if (message is CDrawingMessage_Undo)
            {
                this.Undo();
            }
            else if (message is CDrawingMessage_Line)
            {
                mCurrentMode = CMode.LINE;

                ResetMode();
            }
            else if (message is CDrawingMessage_Freedom)
            {
                mCurrentMode = CMode.FREEDOM;

                ResetMode();
            }
            else if (message is CDrawingMessage_Circle)
            {
                mCurrentMode = CMode.CIRCLE;

                ResetMode();
            }
            else if (message is CDrawingMessage_Ellipse)
            {
                mCurrentMode = CMode.ELLIPSE;

                ResetMode();
            }
            else if (message is CDrawingMessage_Clear)
            {
                this.Clear();
            }
            else if (message is CDrawingMessage_Rectangle)
            {
                mCurrentMode = CMode.RECTANGLE;

                ResetMode();
            }
            else if (message is CDrawingMessage_Pointer)
            {
                mCurrentMode = CMode.POINTER;

                int pointerId = ((CDrawingMessage_Pointer)message).ID;

                Global.prev_ClientID_PointerID_dictionary[mClientID] = pointerId;

                ResetMode();
            }
            else if (message is CDrawingMessage_ClipArt)
            {
                mCurrentMode = CMode.CLIPART;

                int clipArtId = ((CDrawingMessage_ClipArt)message).ID;

                Global.prev_ClientID_ClipArtID_dictionary[mClientID] = clipArtId;

                ResetMode();
            }
            else if (message is CDrawingMessage_ChangeColor)
            {
                CDrawingMessage_ChangeColor cc = (CDrawingMessage_ChangeColor)message;
                Color c = Color.FromArgb(cc.r, cc.g, cc.b);

                Pen pen = Global.GetPenByID(mClientID);
                pen.Color = c;

                this.CreatePen();
            }
            else if (message is CDrawingMessage_ChangeWidth)
            {
                CDrawingMessage_ChangeWidth ct = (CDrawingMessage_ChangeWidth)message;
                
                Pen pen = Global.GetPenByID(mClientID);
                pen.Width = (float) ct.width;

                this.CreatePen();
            }
            else if (message is CDrawingMessage_Undo)
            {
                this.Undo();
            }
            
        }

        public void Clear()
        {
            int n = m_drawingObjects.Count;

            for(int i = 0; i < n; i++)
            {
                m_globalDrawingObjects.Remove(m_drawingObjects[i]);    
            }

            m_drawingObjects.Clear();

            mCount = 0;

            ResetMode();
        }

        public bool enable_move_up = false;

        private bool bPointerAvailable = false;

        public void On_CDrawingMessage_Action_POINTER(CDrawingMessage_Action message)
        {
            CDrawingMessage_Action action = (CDrawingMessage_Action)message;

            if (action.Action == CActionKind.TOUCH_DOWN)
            {
                mCurrentPointer.x = (int)(action.X * Global.SCREEN_WIDTH);
                mCurrentPointer.y = (int)(action.Y * Global.SCREEN_HEIGHT);

                enable_move_up = true;

                bPointerAvailable = true;
            }
            else if (action.Action == CActionKind.TOUCH_MOVE)
            {
                if (enable_move_up)
                {
                    mCurrentPointer.x = (int)(action.X * Global.SCREEN_WIDTH);
                    mCurrentPointer.y = (int)(action.Y * Global.SCREEN_HEIGHT);

                    bPointerAvailable = true;
                }
            }
            else if (action.Action == CActionKind.TOUCH_UP)
            {
                if (enable_move_up)
                {
                    mCurrentPointer.x = (int)(action.X * Global.SCREEN_WIDTH);
                    mCurrentPointer.y = (int)(action.Y * Global.SCREEN_HEIGHT);

                    enable_move_up = false;

                    bPointerAvailable = false;
                }
            }
        }

        private bool bClipArtAvailable = false;

        public void On_CDrawingMessage_Action_CLIPART(CDrawingMessage_Action message)
        {
            CDrawingMessage_Action action = (CDrawingMessage_Action)message;

            if (action.Action == CActionKind.TOUCH_DOWN)
            {
                mCurrentClipArt.Rect.X = (int)(action.X * Global.SCREEN_WIDTH);
                mCurrentClipArt.Rect.Y = (int)(action.Y * Global.SCREEN_HEIGHT);
                mCurrentClipArt.Rect.Width = 1;
                mCurrentClipArt.Rect.Height = 1;

                enable_move_up = true;

                bClipArtAvailable = true;
            }
            else if (action.Action == CActionKind.TOUCH_MOVE)
            {
                if (enable_move_up)
                {
                    mCurrentClipArt.Rect.Width = (int)(action.X * Global.SCREEN_WIDTH) - mCurrentClipArt.Rect.X;
                    mCurrentClipArt.Rect.Height = (int)(action.Y * Global.SCREEN_HEIGHT) - mCurrentClipArt.Rect.Y;

                    bClipArtAvailable = true;
                }
            }
            else if (action.Action == CActionKind.TOUCH_UP)
            {
                if (enable_move_up)
                {
                    mCurrentClipArt.Rect.Width = (int)(action.X * Global.SCREEN_WIDTH) - mCurrentClipArt.Rect.X;
                    mCurrentClipArt.Rect.Height = (int)(action.Y * Global.SCREEN_HEIGHT) - mCurrentClipArt.Rect.Y;

                    enable_move_up = false;

                    bClipArtAvailable = false;

                   this.addToDrawingObjects(mCurrentClipArt);

                    int id = Global.prev_ClientID_ClipArtID_dictionary[mClientID];
                    mCurrentClipArt = new CClipArt(id);
                }
            }
        }


        public void On_CDrawingMessage_Action_RECTANGLE(CDrawingMessage_Action message)
        {
            CDrawingMessage_Action action = (CDrawingMessage_Action)message;

            if (action.Action == CActionKind.TOUCH_DOWN)
            {
                mCurrentRectangle.pen = new Pen(this.mCurrentPen.Color, this.mCurrentPen.Width);
                mCurrentRectangle.x1 = (int)(action.X * Global.SCREEN_WIDTH);
                mCurrentRectangle.y1 = (int)(action.Y * Global.SCREEN_HEIGHT);

                enable_move_up = true;
            }
            else if (action.Action == CActionKind.TOUCH_MOVE)
            {
                if (enable_move_up)
                {
                    mCurrentRectangle.x2 = (int)(action.X * Global.SCREEN_WIDTH);
                    mCurrentRectangle.y2 = (int)(action.Y * Global.SCREEN_HEIGHT);

                    mCurrentRectangle.InitOtherParameters();
                }
            }
            else if (action.Action == CActionKind.TOUCH_UP)
            {
                if (enable_move_up)
                {
                    mCurrentRectangle.x2 = (int)(action.X * Global.SCREEN_WIDTH);
                    mCurrentRectangle.y2 = (int)(action.Y * Global.SCREEN_HEIGHT);

                    mCurrentRectangle.InitOtherParameters();

                    this.addToDrawingObjects(mCurrentRectangle);

                    mCurrentRectangle = new CRectangle();
                    mCurrentRectangle.pen = new Pen(this.mCurrentPen.Color, this.mCurrentPen.Width);

                    enable_move_up = false;
                }
            }
        }

        public void On_CDrawingMessage_Action_ELLIPSE(CDrawingMessage_Action message)
        {
            CDrawingMessage_Action action = (CDrawingMessage_Action)message;

            if (action.Action == CActionKind.TOUCH_DOWN)
            {
                mCurrentEllipse.pen = new Pen(this.mCurrentPen.Color, this.mCurrentPen.Width);
                mCurrentEllipse.XI = (int)(action.X * Global.SCREEN_WIDTH);
                mCurrentEllipse.YI = (int)(action.Y * Global.SCREEN_HEIGHT);
                
                enable_move_up = true;
            }
            else if (action.Action == CActionKind.TOUCH_MOVE)
            {
                if (enable_move_up)
                {
                    mCurrentEllipse.X = (int)(action.X * Global.SCREEN_WIDTH);
                    mCurrentEllipse.Y = (int)(action.Y * Global.SCREEN_HEIGHT);

                    mCurrentEllipse.InitOtherParameters();
                }
            }
            else if (action.Action == CActionKind.TOUCH_UP)
            {
                if (enable_move_up)
                {
                    mCurrentEllipse.X = (int)(action.X * Global.SCREEN_WIDTH);
                    mCurrentEllipse.Y = (int)(action.Y * Global.SCREEN_HEIGHT);

                    mCurrentEllipse.InitOtherParameters();

                    this.addToDrawingObjects(mCurrentEllipse);

                    mCurrentEllipse = new CEllipse();
                    mCurrentEllipse.pen = new Pen(this.mCurrentPen.Color, this.mCurrentPen.Width);

                    enable_move_up = false;
                }
            }
        }

        public void On_CDrawingMessage_Action_CIRCLE(CDrawingMessage_Action message)
        {
            CDrawingMessage_Action action = (CDrawingMessage_Action)message;

            if (action.Action == CActionKind.TOUCH_DOWN)
            {
                mCurrentCircle.pen = new Pen(this.mCurrentPen.Color, this.mCurrentPen.Width);
                mCurrentCircle.x = (int)(action.X * Global.SCREEN_WIDTH);
                mCurrentCircle.y = (int)(action.Y * Global.SCREEN_HEIGHT);
                mCurrentCircle.r = 1;

                enable_move_up = true;
            }
            else if (action.Action == CActionKind.TOUCH_MOVE)
            {
                if (enable_move_up)
                {
                    int a = (int)(action.X * Global.SCREEN_WIDTH) - mCurrentCircle.x;
                    int b = (int)(action.Y * Global.SCREEN_HEIGHT) - mCurrentCircle.y;

                    mCurrentCircle.r = (int)System.Math.Sqrt(a * a + b * b);
                }
            }
            else if (action.Action == CActionKind.TOUCH_UP)
            {
                if (enable_move_up)
                {
                    int a = (int)(action.X * Global.SCREEN_WIDTH) - mCurrentCircle.x;
                    int b = (int)(action.Y * Global.SCREEN_HEIGHT) - mCurrentCircle.y;

                    mCurrentCircle.r = (int)System.Math.Sqrt(a * a + b * b);

                    this.addToDrawingObjects(mCurrentCircle);

                    mCurrentCircle = new CCircle();
                    mCurrentCircle.pen = new Pen(this.mCurrentPen.Color, this.mCurrentPen.Width);

                    enable_move_up = false;
                }
            }
        }

        public void On_CDrawingMessage_Action_LINE(CDrawingMessage_Action message)
        {
            CDrawingMessage_Action action = (CDrawingMessage_Action)message;

            if (action.Action == CActionKind.TOUCH_DOWN)
            {
                mCurrentline.x1 = mCurrentline.x2 = (int)(action.X * Global.SCREEN_WIDTH);
                mCurrentline.y1 = mCurrentline.y2 = (int)(action.Y * Global.SCREEN_HEIGHT);

                enable_move_up = true;
            }
            else if (action.Action == CActionKind.TOUCH_MOVE)
            {
                if (enable_move_up)
                {
                    mCurrentline.x2 = (int)(action.X * Global.SCREEN_WIDTH);
                    mCurrentline.y2 = (int)(action.Y * Global.SCREEN_HEIGHT);
                }
            }
            else if (action.Action == CActionKind.TOUCH_UP)
            {
                if (enable_move_up)
                {
                    mCurrentline.x2 = (int)(action.X * Global.SCREEN_WIDTH);
                    mCurrentline.y2 = (int)(action.Y * Global.SCREEN_HEIGHT);

                    CLine line = new CLine();
                    line.pen = new Pen(this.mCurrentPen.Color, this.mCurrentPen.Width);
                    line.x1 = mCurrentline.x1;
                    line.y1 = mCurrentline.y1;
                    line.x2 = mCurrentline.x2;
                    line.y2 = mCurrentline.y2;

                    mCurrentline = new CLine();
                    mCurrentline.pen = new Pen(this.mCurrentPen.Color, this.mCurrentPen.Width);

                    this.addToDrawingObjects(line);

                    enable_move_up = false;
                }
            }
        }

        public void On_CDrawingMessage_Action_FREEDOM(CDrawingMessage_Action message)
        {
            CDrawingMessage_Action action = (CDrawingMessage_Action)message;

            if (action.Action == CActionKind.TOUCH_DOWN)
            {
                mCurrentline.x1 = mCurrentline.x2 = (int)(action.X * Global.SCREEN_WIDTH);
                mCurrentline.y1 = mCurrentline.y2 = (int)(action.Y * Global.SCREEN_HEIGHT);

                enable_move_up = true;
            }
            else if (action.Action == CActionKind.TOUCH_MOVE)
            {
                if (enable_move_up)
                {
                    mCurrentline.x2 = (int)(action.X * Global.SCREEN_WIDTH);
                    mCurrentline.y2 = (int)(action.Y * Global.SCREEN_HEIGHT);

                    if (mCurrentline.x1 != mCurrentline.x2 || mCurrentline.y1 != mCurrentline.y2)
                    {
                        CLine line = new CLine();
                        line.pen = new Pen(this.mCurrentPen.Color, this.mCurrentPen.Width);
                        line.x1 = mCurrentline.x1;
                        line.y1 = mCurrentline.y1;
                        line.x2 = mCurrentline.x2;
                        line.y2 = mCurrentline.y2;


                        mCurrentline = new CLine();
                        mCurrentline.pen = new Pen(this.mCurrentPen.Color, this.mCurrentPen.Width);
                        mCurrentline.x1 = mCurrentline.x2 = line.x2;
                        mCurrentline.y1 = mCurrentline.y2 = line.y2;


                        this.addToDrawingObjects(line);
                    }
                }
            }
            else if (action.Action == CActionKind.TOUCH_UP)
            {
                if (enable_move_up)
                {
                    mCurrentline.x2 = (int)(action.X * Global.SCREEN_WIDTH);
                    mCurrentline.y2 = (int)(action.Y * Global.SCREEN_HEIGHT);

                    if (mCurrentline.x1 != mCurrentline.x2 || mCurrentline.y1 != mCurrentline.y2)
                    {
                        CLine line = new CLine();
                        line.pen = new Pen(this.mCurrentPen.Color, this.mCurrentPen.Width);
                        line.x1 = mCurrentline.x1;
                        line.y1 = mCurrentline.y1;
                        line.x2 = mCurrentline.x2;
                        line.y2 = mCurrentline.y2;


                        mCurrentline = new CLine();
                        mCurrentline.pen = new Pen(this.mCurrentPen.Color, this.mCurrentPen.Width);
                        mCurrentline.x1 = mCurrentline.x2 = line.x2;
                        mCurrentline.y1 = mCurrentline.y2 = line.y2;


                        this.addToDrawingObjects(line);
                    }

                    enable_move_up = false;
                }
            }
        }

        public void addToDrawingObjects(CDrawingObject drawingObject)
        {
            if (mCount < m_drawingObjects.Count)
            {
                int n = m_drawingObjects.Count;

                for (int i = mCount; i < n; i++)
                {
                    m_globalDrawingObjects.Remove(m_drawingObjects[i]);
                }

                m_drawingObjects.RemoveRange(mCount, n - mCount);
            }

            m_drawingObjects.Add(drawingObject);
            mCount++;

            m_globalDrawingObjects.Add(drawingObject);
        }

        public void Undo()
        {
            if (mCount > 0)
            {
                m_drawingObjects[mCount - 1].Visible = false;

                mCount--;
            }
        }

        public void Redo()
        {
            if (mCount < m_drawingObjects.Count)
            {
                mCount++;

                m_drawingObjects[mCount - 1].Visible = true;
            }
        }

        public void Draw(Graphics g)
        {
            //for (int i = 0; i < mCount; i++)
            //{
            //    m_drawingObjects[i].Draw(g);   
            //}

            if (mCurrentMode == CMode.LINE)
            {
                mCurrentline.Draw(g);
            }
            else if (mCurrentMode == CMode.CIRCLE)
            {
                mCurrentCircle.Draw(g);
            }
            else if (mCurrentMode == CMode.ELLIPSE)
            {
                mCurrentEllipse.Draw(g);
            }
            else if (mCurrentMode == CMode.RECTANGLE)
            {
                mCurrentRectangle.Draw(g);
            }
            else if (mCurrentMode == CMode.POINTER)
            {
                if (bPointerAvailable)
                {
                    mCurrentPointer.Draw(g);
                }
            }
            else if (mCurrentMode == CMode.CLIPART)
            {
                if (bClipArtAvailable)
                {
                    mCurrentClipArt.Draw(g);

                    g.DrawRectangle(
                        new Pen(Color.Red, 2), 
                        Global.CreateRectangle(
                            mCurrentClipArt.Rect.X,
                            mCurrentClipArt.Rect.Y,
                            mCurrentClipArt.Rect.Width,
                            mCurrentClipArt.Rect.Height)
                            );
                }
            }
        }
    }
}
